#!/usr/bin/python
# -*- coding: utf-8 -*-

class SPARC_DISASSEMBLER:
	def sparc_asr_name(self, asr_val):
		if(asr_val == 0):
			asr_name  = "%%y"
		else:
			asr_name  = ("%%asr_%d" % (asr_val))
		return asr_name

	def sparc_rd_reg_name(self, rd_val):
		rd_type_tuple = ("g","o","l","i")
		rd_type       = (rd_val >> 3) & 0x3
		rd_num        = (rd_val     ) & 0x7
		rd_name       = ("%%%c%d" % (rd_type_tuple[rd_type], rd_sub))
		return rd_name

	def sparc_f_reg_name(self, f_val):
		f_name        = ("%%f%d" % (f_val))
		return f_name

	def sparc_get_simm22(self, addr, disp22):
		simm22 = disp22 << 2
		if(disp22 & 0x00200000):
			simm22 |= 0xFF000000

		simm22 = (simm22 + addr) & 0xFFFFFFFF

		return simm22

	def sparc_disassemble_format0(self, addr, data):
		opcode  = ""
		oprand  = ""

		sparc_op     = (data >> 30) & 0x3

		type0_rd     = (data >> 25) & 0x0000001F
		type0_a      = (data >> 29) & 0x00000001
		type0_cond   = (data >> 25) & 0x0000000F

		type0_op2    = (data >> 22) & 0x00000007

		type0_disp22 = (data      ) & 0x003FFFFF
		type0_imm22  = (data      ) & 0x003FFFFF

		sparc_type0_cc_dict  = {2: ("bn","be","ble","bl","bleu","bcs","bneg","bvs",  \
									"ba","bne","bg","bge","bgu","bcc","bpos","bvc"), \
								6: ("fbn","fbne","fblg","fbul","fbl","fbug","fbg","fbu", \
									"fba","fbe","fbue","fbge","fbuge","fble","fbule","fbo"), \
								7: ("cbn","cb123","cb12","cb13","cb1","cb23","cb2","cb3", \
									"cba","cb0","cb03","cb02","cb023","cb01","cb013","cb012")}
		if(type0_op2 == 0):
			opcode = "unimp"
			oprand = ("0x%08X" % data)
		elif(type0_op2 == 4):
			if((type0_rd == 0) and (type0_imm22 == 0)):
				opcode = "nop"
				oprand = ""
			else:
				rd_name = sparc_rd_reg_name(type0_rd)
				tmp     = type0_imm22 << 10
				if(type0_imm22 == 0x003FFFFF):
					opcode = "set"
					oprand = ("0x%08X, %s" % (tmp, rd_name))
				else:
					opcode = "sethi"
					oprand = ("%%hi(0x%08X), %s" % (tmp, rd_name))
		elif((type0_op2 == 2) or (type0_op2 == 6) or (type0_op2 == 7)):
			opcode = sparc_type0_cc_dict[type0_op2][type0_cond]
			if(type0_a == 1):
				opcode = opcode + ",a"
			oprand = ("0x%08X" % (sparc_get_simm22(addr, disp22)))

		return {"opcode":opcode, "oprand":oprand}

	def sparc_disassemble_format1(self, addr, data):
		opcode  = ""
		oprand  = ""

		sparc_op     = (data >> 30) & 0x3

		type1_disp30 = (data      ) & 0x3FFFFFFF

		dist = ((data & 0x3FFFFFFF) << 2) + addr
		opcode = "call"
		oprand = ("0x%08X" % dist)

		return {"opcode":opcode, "oprand":oprand}

	def sparc_disassemble_format2(self, addr, data):
		opcode  = ""
		oprand  = ""

		sparc_op     = (data >> 30) & 0x3

		type2_rd     = (data >> 25) & 0x0000001F
		type2_op3    = (data >> 19) & 0x0000003F
		type2_rs1    = (data >> 14) & 0x0000001F

		type2_opf    = (data >>  5) & 0x000001FF

		type2_i      = (data >> 13) & 0x00000001
		type2_asi    = (data >>  5) & 0x000000FF
		type2_rs2    = (data      ) & 0x0000001F
		type2_simm13 = (data      ) & 0x00001FFF

		return {"opcode":opcode, "oprand":oprand}

	def sparc_opcode_dis(self, addr, data):
		sparc_op     = (data >> 30) & 0x3

		if(sparc_op == 0):
			dis_dict = self.sparc_disassemble_format0(addr, data)
		elif(sparc_op == 1):
			dis_dict = self.sparc_disassemble_format1(addr, data)
		elif(sparc_op == 2):
			dis_dict = self.sparc_disassemble_format2(addr, data)
		elif(sparc_op == 3):
			dis_dict = self.sparc_disassemble_format2(addr, data)

		if(dis_dict["opcode"] == ""):
			opcode_dis = "unknown"
		else:
			opcode_dis = ("%s %s" % (dis_dict["opcode"], dis_dict["oprand"]))

		return opcode_dis
